/**
建造者模式（Builder Pattern）

意图：将一个复杂的构建与其表示相分离，使得同样的构建过程可以创建不同的表示。
主要解决：主要解决在软件系统中，有时候面临着"一个复杂对象"的创建工作，其通常由各个部分的子对象用一定的算法构成；由于需求的变化，这个复杂对象的各个部分经常面临着剧烈的变化，但是将它们组合在一起的算法却相对稳定。
何时使用：一些基本部件不会变，而其组合经常变化的时候。
如何解决：将变与不变分离开。
*/
main(List<String> args) {
  MealBuilder mealBuilder = new MealBuilder();

  Meal vegMeal = mealBuilder.prepareVegMeal();
  print("Veg Meal");
  vegMeal.showItems();
  print("Total Cost: ${vegMeal.getCost()}");

  Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
  print("\n\nNon-Veg Meal");
  nonVegMeal.showItems();
  print("Total Cost: ${nonVegMeal.getCost()}");
}

//////////////////////////////////////////////////////////////////

///
/// 创建一个表示 食物条目 的接口
///
abstract class Item {
  String name();
  Packing packing();
  double price();
}

///
/// 创建一个表示 食物包装 的接口
///
abstract class Packing {
  String pack();
}

///
/// 创建实现 Packing 接口的实体类
///
class Wrapper implements Packing {
  @override
  String pack() {
    return "Wrapper";
  }
}

class Bottle implements Packing {
  @override
  String pack() {
    return "Bottle";
  }
}

///
/// 创建实现 Item 接口的抽象类，该类提供了默认的功能
///
abstract class Burger implements Item {
  @override
  Packing packing() {
    return new Wrapper();
  }

  @override
  double price();
}

abstract class ColdDrink implements Item {
  @override
  Packing packing() {
    return new Bottle();
  }

  @override
  double price();
}

///
/// 创建扩展了 Burger 和 ColdDrink 的实体类
///
class VegBurger extends Burger {
  @override
  double price() {
    return 25.0;
  }

  @override
  String name() {
    return "Veg Burger";
  }
}

class ChickenBurger extends Burger {
  @override
  double price() {
    return 50.5;
  }

  @override
  String name() {
    return "Chicken Burger";
  }
}

class Coke extends ColdDrink {
  @override
  double price() {
    return 30.0;
  }

  @override
  String name() {
    return "Coke";
  }
}

class Pepsi extends ColdDrink {
  @override
  double price() {
    return 35.0;
  }

  @override
  String name() {
    return "Pepsi";
  }
}

///
/// 创建一个 Meal 类，带有上面定义的 Item 对象
///
class Meal {
  List<Item> _items = List<Item>();

  void addItem(Item item) {
    _items.add(item);
  }

  double getCost() {
    double cost = 0.0;
    for (Item item in _items) {
      cost += item.price();
    }
    return cost;
  }

  void showItems() {
    for (Item item in _items) {
      print("Item : ${item.name()}");
      print(", Packing : ${item.packing().pack()}");
      print(", Price : ${item.price()}");
    }
  }
}

///
/// 创建一个 MealBuilder 类，实际的 builder 类负责创建 Meal 对象
///
class MealBuilder {
  Meal prepareVegMeal() {
    Meal meal = new Meal();
    meal.addItem(new VegBurger());
    meal.addItem(new Coke());
    return meal;
  }

  Meal prepareNonVegMeal() {
    Meal meal = new Meal();
    meal.addItem(new ChickenBurger());
    meal.addItem(new Pepsi());
    return meal;
  }
}
